﻿using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.IdentityFramework;
using Abp.Linq.Extensions;
using Abp.MultiTenancy;
using AbpProjectTemplate.Application.Roles.Dtos;
using AbpProjectTemplate.Application.Roles.Filters;
using AbpProjectTemplate.Components.Auditing;
using AbpProjectTemplate.Components.Authorization;
using AbpProjectTemplate.Domain.Roles;
using AbpProjectTemplate.Domain.Users;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace AbpProjectTemplate.Application.Roles
{
    /// <summary>
    /// 角色
    /// </summary>
    [AppAuthorize(AppPermissions.System.RoleManage)]
    [AppAuditTag("角色")]
    public class RoleAppService : AsyncCrudApplicationService<Role, int, RoleDto, RoleListDto, RoleGetPagedListFilter, RoleEditDto>
    {
        private readonly RoleManager _roleManager;
        private readonly UserManager _userManager;

        public RoleAppService(IRepository<Role> repository, RoleManager roleManager, UserManager userManager)
            : base(repository)
        {
            this._roleManager = roleManager;
            this._userManager = userManager;
        }

        protected override async Task<Role> GetEntityByIdAsync(int id)
        {
            return await this.Repository.GetAllIncluding(x => x.Permissions).FirstOrDefaultAsync(x => x.Id == id);
        }

        protected override IQueryable<Role> CreateFilteredQuery(RoleGetPagedListFilter input)
        {
            return this.Repository.GetAllIncluding(x => x.Permissions)
                .WhereIf(!input.Keywords.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Keywords)
                || x.Description.Contains(input.Keywords));
        }


        //protected override IQueryable<Role> ApplySorting(IQueryable<Role> query, RoleGetPagedListFilter input)
        //{
        //    return query.OrderBy(r => r.Name);
        //}

        protected virtual void CheckErrors(IdentityResult identityResult)
        {
            identityResult.CheckErrors(this.LocalizationManager);
        }

        /// <summary>
        /// 角色创建
        /// </summary>
        [AppAudited("创建")]
        public override async Task<RoleDto> Create(RoleEditDto input)
        {
            this.CheckCreatePermission();

            var role = this.ObjectMapper.Map<Role>(input);
            role.Id = 0;
            role.SetNormalizedName();
            role.Name = Guid.NewGuid().ToString("N");

            this.CheckErrors(await this._roleManager.CreateAsync(role));

            var grantedPermissions = this.PermissionManager
                .GetAllPermissions()
                .Where(p => input.GrantedPermissions.Contains(p.Name))
                .ToList();

            await this._roleManager.SetGrantedPermissionsAsync(role, grantedPermissions);

            return this.MapToEntityDto(role);
        }
        /// <summary>
        /// 获取所有角色
        /// </summary>
        public async Task<IEnumerable<RoleListDto>> GetAll()
        {
            var items = await this.Repository.GetAllListAsync();

            return this.ObjectMapper.Map<IEnumerable<RoleListDto>>(items);
        }
        /// <summary>
        /// 获取所有权限
        /// </summary>
        public ListResultDto<PermissionDto> GetAllPermissions()
        {
            var multiTenancySides = MultiTenancySides.Host;
            if (this.AbpSession.TenantId.HasValue)
                multiTenancySides = MultiTenancySides.Tenant;
            var permissions = this.PermissionManager.GetAllPermissions(multiTenancySides)
                .Where(t => t.Parent == null)
                .Select(t => new PermissionDto()
                {
                    Name = t.Name,
                    DisplayName = t.DisplayName.ToString(),
                    Description = t.Description?.ToString(),
                    Children = t.Children.Where(x => x.MultiTenancySides.HasFlag(multiTenancySides))
                                         .Select(x => new PermissionDto()
                                         {
                                             DisplayName = x.DisplayName.ToString(),
                                             Description = x.Description?.ToString(),
                                             Name = x.Name
                                         })
                });
            return new ListResultDto<PermissionDto>(permissions.ToList());
            //return Task.FromResult(new ListResultDto<PermissionDto>(
            //    ObjectMapper.Map<List<PermissionDto>>(permissions).OrderBy(p => p.DisplayName).ToList()
            //));
        }
        /// <summary>
        /// 修改
        /// </summary>
        [AppAudited("修改")]
        public override async Task<RoleDto> Update(RoleEditDto input)
        {
            this.CheckUpdatePermission();

            var role = await this._roleManager.GetRoleByIdAsync(input.Id);

            this.ObjectMapper.Map(input, role);

            this.CheckErrors(await this._roleManager.UpdateAsync(role));
            //系统管理员不需要配置权限。
            if (role.Name != AppRoleConfig.AdminRoleName)
            {
                var grantedPermissions = this.PermissionManager
                    .GetAllPermissions()
                    .Where(p => input.GrantedPermissions.Contains(p.Name))
                    .ToList();

                await this._roleManager.SetGrantedPermissionsAsync(role, grantedPermissions);
            }
            return this.MapToEntityDto(role);
        }
        /// <summary>
        /// 删除
        /// </summary>
        [AppAudited("删除")]
        public override async Task Delete(EntityDto<int> input)
        {
            this.CheckDeletePermission();

            var role = await this._roleManager.FindByIdAsync(input.Id.ToString());
            var users = await this._userManager.GetUsersInRoleAsync(role.NormalizedName);

            foreach (var user in users)
            {
                this.CheckErrors(await this._userManager.RemoveFromRoleAsync(user, role.NormalizedName));
            }

            this.CheckErrors(await this._roleManager.DeleteAsync(role));
        }
    }
}



